#pragma once
#include "CGIPrefix.h"
#include "CGIContext.h"
#include "CGIResource.h"
namespace Alice
{
    class CGICommandListBase;
    class CGICommand
    {
    public:
        CGICommand*mNext;
        virtual void ExecuteAndDestruct(CGICommandListBase&inCmdList) = 0;
    };
    template <typename CGICmdListType, typename LAMBDA>
    struct TRHILambdaCommand final : public CGICommand
    {
        LAMBDA Lambda;
        TRHILambdaCommand(LAMBDA&& inLambda)
            : Lambda(std::forward<LAMBDA>(inLambda))
        {}

        void ExecuteAndDestruct(CGICommandListBase& inCmdList) override final
        {
            Lambda(*static_cast<CGICmdListType*>(&inCmdList));
            Lambda.~LAMBDA();
        }
    };
    #define ALLOC_COMMAND(...) new ( AllocCommand(sizeof(__VA_ARGS__), alignof(__VA_ARGS__)) ) __VA_ARGS__
    class CGICommandListBase
    {
    public:
        CGICommandListBase();
        void* AllocCommand(int32 AllocSize, int32 Alignment)
        {
            void*ptr=malloc(AllocSize);
            CGICommand* Result = (CGICommand*) ptr;
            ++NumCommands;
            *CommandLink = Result;
            CommandLink = &Result->mNext;
            return Result;
        }
        template <typename LAMBDA>
        void EnqueueLambda(LAMBDA&& Lambda)
        {
            if (IsBottomOfPipe())
            {
                Lambda(*this);
            }
            else
            {
                printf("size is %u\n",sizeof(TRHILambdaCommand<CGICommandListBase, LAMBDA>));
                ALLOC_COMMAND(TRHILambdaCommand<CGICommandListBase, LAMBDA>)(std::forward<LAMBDA>(Lambda));
            }
        }
        FORCEINLINE bool IsBottomOfPipe() const
        {
            return false;
        }
        CGICommand*Root;
        CGICommand**CommandLink;
        // The active context into which graphics commands are recorded.
        ICGICommandContext* GraphicsContext = nullptr;

        // The active compute context into which (possibly async) compute commands are recorded.
        //ICGIComputeContext* ComputeContext  = nullptr;

        // The active upload context into which RHI specific commands are recorded.
        //IRHIUploadContext* UploadContext 	= nullptr;
        int NumCommands;
        ICGICommandContext&GetContext()
        {
            return *GraphicsContext;
        }
    };
    class ComputeCommandList:public CGICommandListBase
    {
    public:
    };
    class CGICommandList:public ComputeCommandList
    {
    public:
        void BeginRenderPass(const CGIRenderPassInfo* InInfo, const TCHAR* Name);
    };
    class CGICommandListImmediate : public CGICommandList
    {
    public:
	    static CGICommandListImmediate& Get();
        struct FQueuedCommandList
        {
            // The command list to enqueue.
            CGICommandListBase* CmdList = nullptr;
            FQueuedCommandList() = default;
            FQueuedCommandList(CGICommandListBase* InCmdList)
                : CmdList(InCmdList)
            {}
        };
    };
    
    class CGICommandListScopedExtendResourceLifetime
    {
    public:
        CGICommandListScopedExtendResourceLifetime(CGICommandListImmediate& InRHICmdList)
            : mCGICmdList(InRHICmdList)
        {
            //RHIResourceLifetimeAddRef();
        }

        ~CGICommandListScopedExtendResourceLifetime()
        {
            //RHIResourceLifetimeReleaseRef(RHICmdList);
        }

    private:
        CGICommandListImmediate& mCGICmdList;
    };
    class CGICommandListExecutor
    {
    public:
	    CGICommandListImmediate mCommandListImmediate;
	    static inline CGICommandListImmediate& GetImmediateCommandList();
    };
    extern CGICommandListExecutor gCGICommandListExecutor;
}